package Panel;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JLabel;
import javax.swing.SwingConstants;

import spread.AdvancedMessageListener;
import spread.SpreadConnection;
import spread.SpreadException;
import spread.SpreadGroup;
import spread.SpreadMessage;
import Flight.Flight;
import Mensajes.MensajeEstado;
import Mensajes.Mensaje_Num_Paneles;
import Operaciones.Constantes;

public class PanelDeparture extends Panel implements AdvancedMessageListener{
	private static final long serialVersionUID = 3095155158733993182L;
	
	private JLabel infoDeparture = new JLabel("<html>&nbsp;&nbsp&nbsp;&nbsp;&nbsp&nbsp;&nbsp;&nbsp&nbsp;HORA SALIDA DEL VUELO&nbsp;&nbsp;&nbsp&nbsp;&nbsp;&nbsp;|&nbsp;DES&nbsp;|&nbsp;Nº VUELO&nbsp;|&nbsp;D&nbsp;|&nbsp;HORA DE EMBARQUE DEL VUELO&nbsp;|&nbsp;P&nbsp;|&nbsp;EST&nbsp; <p>");
	private JLabel departures = new JLabel();
	// Conexion con Spread
	private SpreadConnection connection;
	private SpreadGroup groupSalidas;
	
	// Parametros del panel.
	private int puerto;
	private int n_max_encendidos;
	private ArrayList<EstadoPanel> estadosPaneles = new ArrayList<EstadoPanel>();

	private boolean encendido = true;
	private int prioridad = 0;
	
	public PanelDeparture (String pnombrePanel, int ppuerto, int pn_max_encendidos, int pprioridad)
	{
		super(pnombrePanel);
		
		this.nombrePanel = pnombrePanel;
		this.puerto = ppuerto;
		this.n_max_encendidos = pn_max_encendidos;
		this.prioridad = pprioridad;
		
		this.setSize(Constantes.ANCHO_VENTANA,Constantes.ALTO_VENTANA);
		this.setLayout(new GridBagLayout());
		inicializarPanel();
	    this.setVisible(true);
	    
	    // Creamos al conexion con Spread
	    this.connection = new SpreadConnection();
	    try {
			this.connection.connect(null, puerto, pnombrePanel, false, true);
			this.connection.add(this);
			
			// Me agrego al grupo de llegadas para recibir sus mensajes.
			this.groupSalidas = new SpreadGroup();
			this.groupSalidas.join(connection, Constantes.GRUPO_SALIDAS);
		} catch (SpreadException e) {
			Constantes.mensajeError("Problema al crear la conexion con Spread (Panel de salidas)");
			System.exit(-1);
		}
		// Fin conexión con Spread
	}
	protected void remove (Flight f){
		// No realizamos nada en este método.
	}
	
	protected void update (Flight f){
		// No realizamos nada en este método.
	}
	
	protected void inicializarPanel() {
		this.setBackground(Color.BLACK);

		GridBagConstraints c = new GridBagConstraints();
		
		c.weightx = 1.0; c.weighty = 1.0;
		c.fill = GridBagConstraints.NONE;
		c.anchor = GridBagConstraints.CENTER;
		
		c.gridx = 0;
		c.gridy = 0;
			this.titlePanel.setForeground(Color.WHITE);
			this.add(this.titlePanel,c);
		
		c.gridx = 0;
		c.gridy = 1;
			this.infoDeparture.setForeground(Color.CYAN);
			this.add(this.infoDeparture,c);

		String departure_aux = "";
		c.gridx = 0;
		c.gridy = 2;
			this.departures.setText(departure_aux);
			this.departures.setForeground(Color.YELLOW);
			this.departures.setHorizontalAlignment(SwingConstants.CENTER);
			this.add(this.departures,c);
		
		this.setVisible(true);
	}
	
	protected void repaintVuelos (String message){		
		this.departures.setText(message);
	}
	
	public void apagarPanel (){
		
		this.encendido = false;
		actualizarEstado(this.nombrePanel, false);
		sendMessage_NumPanel();

		this.titlePanel.setForeground(Color.BLACK);
		this.infoDeparture.setForeground(Color.BLACK);
		this.departures.setForeground(Color.BLACK);
	}
	
	public void encenderPanel (){
		this.encendido = true;
		
		actualizarEstado(this.nombrePanel, false);
		sendMessage_NumPanel();
		
		this.titlePanel.setForeground(Color.WHITE);
		this.infoDeparture.setForeground(Color.CYAN);
		this.departures.setForeground(Color.YELLOW);
	}
	
	public int numEncendidos (){
		int num_aux = 0;
		Iterator<EstadoPanel> it = this.estadosPaneles.iterator();

		while (it.hasNext()){
			EstadoPanel es = it.next();
			if (es.isEncendido()){
				num_aux++;
			}
		}
		return num_aux;
	}
	
	public boolean menorPrioridad (){
		int num_aux = 0;
		Iterator<EstadoPanel> it = this.estadosPaneles.iterator();
		while (it.hasNext()){
			EstadoPanel es = it.next();
			if (es.isEncendido() && es.getPrioridad() < this.prioridad){
				num_aux++;
			}
		}
		return (num_aux >= this.n_max_encendidos);
	}
	
	public boolean tenemosPanel (String pnombrePanel){
		Iterator<EstadoPanel> it = this.estadosPaneles.iterator();

		while (it.hasNext()){
			EstadoPanel es = it.next();
			if (es.getNombrePanel().equals(pnombrePanel)){
				return true;
			}
		}
		return false;
	}
	
	public boolean actualizarEstado(String pnombrePanel, boolean estado){
		Iterator<EstadoPanel> it = this.estadosPaneles.iterator();

		while (it.hasNext()){
			EstadoPanel es = it.next();
			if (es.getNombrePanel().equals(pnombrePanel)){
				es.setEncendido(estado);
				return true;
			}
		}
		return false;
	}
	
	public void insertamosPanel (String pnombrePanel, boolean pencendido, int pprioridad){
		this.estadosPaneles.add(new EstadoPanel(pnombrePanel, pencendido, pprioridad));
	}
	
	// Método propios del panel
	public boolean sendMessage_NumPanel () {
		// Creamos el mensaje de envio
		SpreadMessage msg = new SpreadMessage();
		try {
			// Creamos el Mensaje de estado asociado a este envio.
			Mensaje_Num_Paneles me = new Mensaje_Num_Paneles(this.encendido,this.prioridad);
			msg.setObject(me);
			msg.setSafe();
			msg.setSelfDiscard(true);
			msg.addGroup(this.groupSalidas);
			connection.multicast(msg);
		} catch (SpreadException e) {
			Constantes.mensajeError("Problema al enviar mensaje al grupo de Terminales");
			return false;
		}
		return true;
	}
	// Fin de método propios del panel.

	
	// Implementamos los metodos necesarios para la interfaz AdvancedMessageListener
	public void regularMessageReceived(SpreadMessage msg){
		String nameMsg = msg.getSender().toString().split("#")[1];
		if (nameMsg.startsWith("TER")){
			MensajeEstado msgEstado = null;
			try {
				msgEstado = (MensajeEstado) msg.getObject();
				repaintVuelos(msgEstado.getTexto());
			} catch (SpreadException e) {
				Constantes.mensajeError("Problema al recibir mensaje de Spread");
			}
		} else if (nameMsg.startsWith("PD")){
			Mensaje_Num_Paneles msgNum = null;
			try {
				msgNum = (Mensaje_Num_Paneles) msg.getObject();
				if (tenemosPanel(nameMsg)){
					actualizarEstado(nameMsg,msgNum.getEncendido());
				} else {
					insertamosPanel(nameMsg,msgNum.getEncendido(),msgNum.getPrioridad());
				}
				int enc = numEncendidos();
				if ((enc >= this.n_max_encendidos) && (menorPrioridad()) && (this.encendido)){
						this.apagarPanel();
				} else if ((enc < this.n_max_encendidos) && (!menorPrioridad()) && (!this.encendido)){
						this.encenderPanel();
				}
			} catch (SpreadException e) {
				Constantes.mensajeError("Problema al recibir mensaje de Spread");
			}
		}
	}
	

	public void membershipMessageReceived(SpreadMessage msg){
		if (msg.getMembershipInfo().isCausedByJoin()){
			// Tenemos que enviar el estado de nuestro panel.
			this.sendMessage_NumPanel();
		} else if (msg.getMembershipInfo().isCausedByDisconnect()){
			String nameMsg = msg.getMembershipInfo().getDisconnected().toString().split("#")[1];
			this.actualizarEstado(nameMsg, false);
			// Tenemos que enviar el estado de nuestro panel.
			this.sendMessage_NumPanel();
		}
	}
	// Fin de la implementación de los métodos de la interfaz
	
	public static void main(String args[]){
		String nombrePanel = "";
		int puerto = 0;
		int n_max_encendidos = 0;
		int prioridad = 0;
		try{
			// Cogemos el nombre del panel.
			nombrePanel = args[0];
			// Cogemos el argumento que será el puerto.
			puerto = Integer.parseInt(args[1]);
			// Cogemos el argumento que será el puerto.
			n_max_encendidos = Integer.parseInt(args[2]);
			// Prioridad del panel.
			prioridad = Integer.parseInt(args[3]);
		}catch (NumberFormatException e){
			Constantes.mensajeError("No válido el puerto, el límite de paneles encendidos o la prioridad del panel");
			System.exit(-1);
		}catch (java.lang.ArrayIndexOutOfBoundsException e ){
			Constantes.mensajeError("Debes de intrucir como argumento el puerto de ejecución");
			System.exit(-1);
		}
		
		// Creamos los dos tipos de paneles
		PanelDeparture pA = new PanelDeparture(nombrePanel, puerto, n_max_encendidos, prioridad);

		new VentanaVuelos(pA,"Próximas salidas de vuelos - " + nombrePanel);
	}
}
